//==========================================================================================
//
//		System.Windows.Forms.AxHost
//		Copyright (c) 2005, OpenNETCF.org
//
//		This library is free software; you can redistribute it and/or modify it under 
//		the terms of the OpenNETCF.org Shared Source License.
//
//		This library is distributed in the hope that it will be useful, but 
//		WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
//		FITNESS FOR A PARTICULAR PURPOSE. See the OpenNETCF.org Shared Source License 
//		for more details.
//
//		You should have received a copy of the OpenNETCF.org Shared Source License 
//		along with this library; if not, email licensing@opennetcf.org to request a copy.
//
//		If you wish to contact the OpenNETCF Advisory Board to discuss licensing, please 
//		email licensing@opennetcf.org.
//
//		For general enquiries, email enquiries@opennetcf.org or visit our website at:
//		http://www.opennetcf.org
//
//==========================================================================================

using System;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Collections;
using System.Collections.Specialized;
using System.Drawing;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Text;
using Microsoft.WindowsCE.Forms;
using System.ComponentModel;

namespace System.Windows.Forms
{
    [System.ComponentModel.DesignTimeVisibleAttribute(false)]
    public partial class AxHost : Control
    {
        private Control parentContainer;
        private IOleInPlaceActiveObject iOleInPlaceActiveObject;
        private IOleObject iOleObject;
        private IOleInPlaceObject iOleInPlaceObject;
        private IOleControl iOleControl;
        private BitVector32 axState;
        private IntPtr wndprocAddr;
        private IntPtr hwndFocus;
        private OleSite oleSite;
        private Guid clsid;
        private int flags;
        private int ocState;
        static private Guid IID_IUnknown = new Guid("{00000000-0000-0000-C000-000000000046}");
        static internal Guid windowsMediaPlayer_Clsid = new Guid("{6bf52a52-394a-11d3-b153-00c04f79faa6}");

        private const int OC_INPLACE = 4;
        private const int OC_LOADED = 1;
        private const int OC_OPEN = 0x10;
        private const int OC_PASSIVE = 0;
        private const int OC_RUNNING = 2;
        private const int OC_UIACTIVE = 8;
 



        private static int ocxStateSet;
        private static int editorRefresh;
        private static int listeningToIdle;
        private static int refreshProperties;
        private static int checkedIppb;
        private static int checkedCP;
        private static int fNeedOwnWindow;
        private static int fOwnWindow;
        private static int fSimpleFrame;
        private static int fFakingWindow;
        private static int rejectSelection;
        private static int ownDisposing;
        private static int sinkAttached;
        private static int disposed;
        private static int manualUpdate;
        private static int addedSelectionHandler;
        private static int valueChanged;
        private static int handlePosRectChanged;
        private static int siteProcessedInputKey;
        private static int needLicenseKey;
        private static int inTransition;
        private static int processingKeyUp;
        private static int assignUniqueID;
        private static int renameEventHooked;
        private object instance;


        AxContainer GetParentContainer() { return null; }

        static AxHost()
        {
            ocxStateSet = BitVector32.CreateMask();
            editorRefresh = BitVector32.CreateMask(ocxStateSet);
            listeningToIdle = BitVector32.CreateMask(editorRefresh);
            refreshProperties = BitVector32.CreateMask(listeningToIdle);
            checkedIppb = BitVector32.CreateMask(refreshProperties);
            checkedCP = BitVector32.CreateMask(checkedIppb);
            fNeedOwnWindow = BitVector32.CreateMask(checkedCP);
            fOwnWindow = BitVector32.CreateMask(fNeedOwnWindow);
            fSimpleFrame = BitVector32.CreateMask(fOwnWindow);
            fFakingWindow = BitVector32.CreateMask(fSimpleFrame);
            rejectSelection = BitVector32.CreateMask(fFakingWindow);
            ownDisposing = BitVector32.CreateMask(rejectSelection);
            sinkAttached = BitVector32.CreateMask(ownDisposing);
            disposed = BitVector32.CreateMask(sinkAttached);
            manualUpdate = BitVector32.CreateMask(disposed);
            addedSelectionHandler = BitVector32.CreateMask(manualUpdate);
            valueChanged = BitVector32.CreateMask(addedSelectionHandler);
            handlePosRectChanged = BitVector32.CreateMask(valueChanged);
            siteProcessedInputKey = BitVector32.CreateMask(handlePosRectChanged);
            needLicenseKey = BitVector32.CreateMask(siteProcessedInputKey);
            inTransition = BitVector32.CreateMask(needLicenseKey);
            processingKeyUp = BitVector32.CreateMask(inTransition);
            assignUniqueID = BitVector32.CreateMask(processingKeyUp);
            renameEventHooked = BitVector32.CreateMask(assignUniqueID);
        }

        protected AxHost(string clsid): this(clsid, 0)
        {
        }

        protected AxHost(string clsid, int flags)
        {
            //this.REGMSG_MSG = SafeNativeMethods.RegisterWindowMessage(Application.WindowMessagesVersion + "_subclassCheck");
            this.axState = new BitVector32();
            this.wndprocAddr = IntPtr.Zero;
            this.Text = "";
            this.hwndFocus = IntPtr.Zero;
            this.oleSite = new AxHost.OleSite(this);
            //this.selectionChangeHandler = new EventHandler(this.OnNewSelection);
            this.clsid = new Guid(clsid);
            this.flags = flags;
            //this.axState[AxHost.assignUniqueID] = !base.GetType().GUID.Equals(AxHost.comctlImageCombo_Clsid);
            this.axState[AxHost.needLicenseKey] = true;
            this.axState[AxHost.rejectSelection] = true;
            //this.onContainerVisibleChanged = new EventHandler(this.OnContainerVisibleChanged);
            if (Handle != IntPtr.Zero)
                this.GetOcx();
        }
 


        public bool PreProcessMessage(ref Message msg)
        {
            return false;
        }

        internal virtual Control ParentInternal
        {
            get
            {
                return Parent;
            }
            set
            {
                if (Parent != value)
                {
                    if (value != null)
                    {
                        value.Controls.Add(this);
                    }
                    else
                    {
                        Parent.Controls.Remove(this);
                    }
                }
            }
        }


        public static COMRECT FillInRect(COMRECT dest, Rectangle source)
        {
            dest.left = source.X;
            dest.top = source.Y;
            dest.right = source.Width + source.X;
            dest.bottom = source.Height + source.Y;
            return dest;
        }

        public COMRECT GetClipRect(COMRECT clipRect)
        {
            if (clipRect != null)
            {
                AxHost.FillInRect(clipRect, new Rectangle(0, 0, 32000, 32000));
            }
            return clipRect;
        }

        public Control ParentContainer
        {
            get { return parentContainer; }
            set { parentContainer = value; }
        }

        public int DoVerb(int verb)
        {
            Control control = this; //.ParentInternal;
            return GetOleObject().DoVerb(verb, IntPtr.Zero, this.oleSite, -1, (control != null) ? control.Handle : IntPtr.Zero, AxHost.FillInRect(new COMRECT(), base.Bounds));
        }

        private IOleObject GetOleObject()
        {
            if (iOleObject == null)
            {
                iOleObject = (IOleObject)instance;
            }
            return iOleObject;
        }

        private IOleControl GetOleControl()
        {
            if (iOleControl == null)
            {
                iOleControl = (IOleControl)instance;
            }
            return iOleControl;
        }

        public object GetOcx()
        {
            TransitionUpTo(4);
            return instance;
        }

        private object GetOcxCreate()
        {
            if (this.instance == null)
            {
                this.CreateInstance();
                //this.RealizeStyles();
                this.AttachInterfaces();
                this.oleSite.OnOcxCreate();
            }
            return this.instance;
        }


        protected virtual void AttachInterfaces()
        {
        }


        private void CreateInstance()
        {
            try
            {
                instance = CreateInstanceCore(clsid);
            }
            catch (COMException ex)
            {
                if (ex.ErrorCode == -2147221230)
                {
                    throw new InvalidOperationException("AxHost: unable to find license for the component");
                }
                throw;
            }
            //this.SetOcState(1);
        }

        protected virtual object CreateInstanceCore(Guid clsid)
        {
            // TODO: Add support for controls that require license
            //if (this.IsUserMode())
            //{
            //    this.CreateWithLicense(this.licenseKey, clsid);
            //}
            //else
            //{
                this.CreateWithoutLicense(clsid);
            //}
            return this.instance;
        }

        private void CreateWithoutLicense(Guid clsid)
        {
            instance = CoCreateInstance(ref clsid, null, 1, ref IID_IUnknown);
        }

        private void MakeVisibleWithShow()
        {
            //ContainerControl owner = this.ContainingControl;
            //Control activeCtl = (owner == null) ? null : owner.ActiveControl;
            try
            {
                this.DoVerb(-1);
            }
            catch (Exception)
            {
                //throw new TargetInvocationException(SR.GetString("AXNohWnd", new object[] { base.GetType().Name }), ex);
            }
            catch
            {
                throw;
            }
            this.EnsureWindowPresent();
            //base.CreateControl(true);
            //if ((owner != null) && (owner.ActiveControl != activeCtl))
            //{
            //    owner.ActiveControl = activeCtl;
            //}


        }

        protected virtual void ResizeControl()
        {
            if (instance == null)
                return;
            IOleWindow wnd = GetOcx() as IOleWindow;
            IntPtr hwnd;
            wnd.GetWindow(out hwnd);
            IOleInPlaceObject ipo = GetInPlaceObject();
            COMRECT pos = new COMRECT(this.ClientRectangle);
            ipo.SetObjectRects(pos, pos);

            SetWindowPos(hwnd, SetWindowPosZOrder.HWND_TOP, 0, 0, this.Width, this.Height, SetWindowPosFlags.SWP_SHOWWINDOW);
        }

        protected override void OnResize(EventArgs e)
        {
            ResizeControl();
            base.OnResize(e);
        }

        public bool QuickActivate()
        {
            if (!(instance is IQuickActivate))
            {
                return false;
            }
            IntPtr pQA;
            Guid IID_QUICKACTIVATE = TypeHelper.GetTypeGuid(typeof(IQuickActivate));
            pQA = Marshal.GetComInterfaceForObject(instance, typeof(IQuickActivate));
            IQuickActivate qa = (IQuickActivate)this.instance;
            tagQACONTAINER qacont = new tagQACONTAINER();
            tagQACONTROL qactl = new tagQACONTROL();
            qacont.pClientSite = Marshal.GetComInterfaceForObject( this.oleSite, typeof(IOleClientSite));
            qacont.pPropertyNotifySink = Marshal.GetComInterfaceForObject( this.oleSite, typeof(IPropertyNotifySink));
            qacont.pFont = IntPtr.Zero; // this.oleSite; //
            //qacont.pFont = AxHost.FontToIFont(this.GetParentContainer().parent.Font);
            qacont.dwAppearance = 0;
            qacont.lcid = CultureInfo.CurrentCulture.LCID;
            Control ctlParent = this.ParentInternal;
            if (ctlParent != null)
            {
                qacont.colorFore = (uint)ColorTranslator.ToOle(ctlParent.ForeColor);
                qacont.colorBack = (uint)ColorTranslator.ToOle(ctlParent.BackColor);
            }
            else
            {
                qacont.colorFore = (uint)ColorTranslator.ToOle(SystemColors.WindowText);
                qacont.colorBack = (uint)ColorTranslator.ToOle(SystemColors.Window);
            }
            qacont.dwAmbientFlags = 0xe0;
            //if (this.IsUserMode())
            //{
            //    qacont.dwAmbientFlags |= 4;
            //}
            try
            {
                IntPtr p1 = Marshal.AllocHGlobal(Marshal.SizeOf(qacont));
                IntPtr p2 = Marshal.AllocHGlobal (Marshal.SizeOf(qactl));
                Marshal.StructureToPtr(qacont, p1, false);
                Marshal.StructureToPtr(qactl, p2, false);
                //qa.QuickActivate(ref qacont, out qactl);
                qa.QuickActivate(p1, p2);
                Marshal.PtrToStructure(p2, qactl);
                Marshal.FreeHGlobal(p2);
                Marshal.FreeHGlobal(p1);
            }
            catch (Exception)
            {
                this.DisposeAxControl();
                return false;
            }
            catch
            {
                this.DisposeAxControl();
                return false;
            }
            //this.miscStatusBits = qactl.dwMiscStatus;
            //this.ParseMiscBits(this.miscStatusBits);
            return true;
        }

        public int SlowActivate()
        {
            return this.GetOleObject().SetClientSite(this.oleSite);
            //bool flag1 = false;
            //if ((this.miscStatusBits & 0x20000) != 0)
            //{
            //    flag1 = true;
            //}
            //this.DepersistControl();
        }
 


        [DllImport("coredll")]
        extern static IntPtr LocalAlloc(int flags, int cb);

        private void DisposeAxControl()
        {
            if (this.GetParentContainer() != null)
            {
                this.GetParentContainer().RemoveControl(this);
            }
            this.TransitionDownTo(2);
            if (this.GetOcState() == 2)
            {
                this.GetOleObject().SetClientSite(null);
                this.SetOcState(1);
            }
        }

        private IOleInPlaceObject GetInPlaceObject()
        {
            if (iOleInPlaceObject == null)
            {
                iOleInPlaceObject = (IOleInPlaceObject)this.instance;
            }
            return this.iOleInPlaceObject;
        }

        private void SetAxState(int mask, bool value)
        {
            this.axState[mask] = value;
        }

        private bool GetAxState(int mask)
        {
            return this.axState[mask];
        }

        private bool GetSiteOwnsDeactivation()
        {
            return axState[AxHost.ownDisposing];
        }

        protected override void OnHandleCreated(EventArgs e)
        {
        }

        protected override void OnParentChanged(EventArgs e)
        {
        }

        protected override Control.ControlCollection CreateControlsInstance()
        {
            Control.ControlCollection ret = base.CreateControlsInstance();
            if (instance == null)
            {
                TransitionUpTo(4);
            }
            return ret;
        }
        private IntPtr GetHandleNoCreate()
        {
            return base.Handle;
        }

        private int GetOcState()
        {
            return this.ocState;
        }

        private void SetOcState(int nv)
        {
            this.ocState = nv;
        }

        private int UiDeactivate()
        {
            bool ownsDisp = this.axState[AxHost.ownDisposing];
            this.axState[AxHost.ownDisposing] = true;
            int ret = 0;
            try
            {
                ret = this.GetInPlaceObject().UIDeactivate();
            }
            finally
            {
                this.axState[AxHost.ownDisposing] = ownsDisp;
            }
            return ret;
        }

        protected virtual void DetachSink()
        {
            lock (this)
            {
            }
        }
        private void StartEvents()
        {
            if (!this.axState[AxHost.sinkAttached])
            {
                try
                {
                    this.CreateSink();
                    this.oleSite.StartEvents();
                }
                catch (Exception)
                {
                }
                catch
                {
                }
                this.axState[AxHost.sinkAttached] = true;
            }
        }

        private void StopEvents()
        {
            if (this.axState[AxHost.sinkAttached])
            {
                try
                {
                    this.DetachSink();
                }
                catch (Exception)
                {
                }
                catch
                {
                }
                this.axState[AxHost.sinkAttached] = false;
            }
            this.oleSite.StopEvents();
        }

        protected virtual void CreateSink()
        {
            lock (this)
            {
            }
        }

        private void ReleaseAxControl()
        {
            //this.NoComponentChangeEvents++;
            //ContainerControl control1 = this.ContainingControl;
            //if (control1 != null)
            //{
            //    control1.VisibleChanged -= this.onContainerVisibleChanged;
            //}
            try
            {
                if (this.instance != null)
                {
                    Marshal.FinalReleaseComObject(this.instance);
                    this.instance = null;
                    this.iOleInPlaceObject = null;
                    this.iOleObject = null;
                    this.iOleControl = null;
                    this.iOleInPlaceActiveObject = null;
                }
                this.axState[AxHost.checkedIppb] = false;
                this.axState[AxHost.checkedCP] = false;
                this.axState[AxHost.disposed] = true;
                this.axState[AxHost.sinkAttached] = false;
                this.wndprocAddr = IntPtr.Zero;
                this.SetOcState(0);
            }
            finally
            {
                //this.NoComponentChangeEvents--;
            }
        }

        private void InPlaceDeactivate()
        {
            this.axState[AxHost.ownDisposing] = true;
            //ContainerControl container = this.ContainingControl;
            //if ((container != null) && (container.ActiveControl == this))
            //{
            //    container.ActiveControl = null;
            //}
            try
            {
                this.GetInPlaceObject().InPlaceDeactivate();
            }
            catch (Exception)
            {
            }
            catch
            {
            }
        }

        private void DestroyFakeWindow()
        {
            this.axState[AxHost.fFakingWindow] = false;
            //base.DestroyHandle();
        }

        private void InPlaceActivate()
        {
            try
            {
                this.DoVerb(-5);
            }
            catch (Exception )
            {
                throw ;
            }
            catch
            {
                throw;
            }
            this.EnsureWindowPresent();
        }

        private void EnsureWindowPresent()
        {
            if (base.Handle == IntPtr.Zero)
            {
                try
                {
                    ((IOleClientSite)this.oleSite).ShowObject();
                }
                catch
                {
                }
            }
            if (base.Handle == IntPtr.Zero && (this.ParentInternal != null))
            {
                throw new InvalidOperationException("AXNohWnd");
            }
        }
 

        private void ActivateAxControl()
        {
            if (this.QuickActivate())
            {
                //this.DepersistControl();
            }
            else
            {
                int ret = this.SlowActivate();
                ret = 0;
            }
            this.SetOcState(2);
        }

        private void TransitionUpTo(int state)
        {
            if (!this.axState[AxHost.inTransition])
            {
                try
                {
                    this.axState[AxHost.inTransition] = true;
                    while (state > this.GetOcState())
                    {
                        switch (this.GetOcState())
                        {
                            case 0:
                                {
                                    this.axState[AxHost.disposed] = false;
                                    this.GetOcxCreate();
                                    this.SetOcState(1);
                                    continue;
                                }
                            case 1:
                                {
                                    this.ActivateAxControl();
                                    this.SetOcState(2);
                                    //if (this.IsUserMode())
                                    //{
                                        this.StartEvents();
                                    //}
                                    continue;
                                }
                            case 2:
                                {
                                    this.axState[AxHost.ownDisposing] = false;
                                    if (!this.axState[AxHost.fOwnWindow])
                                    {
                                        this.InPlaceActivate();
                                        //Debug
                                        MakeVisibleWithShow();
                                        COMRECT rc = new COMRECT();
                                        FillInRect(rc, this.ClientRectangle);
                                        GetInPlaceObject().SetObjectRects(rc, rc);
                                        if ((base.Visible /*|| (this.ContainingControl == null)) || !this.ContainingControl.Visible*/))
                                        {
                                            goto Label_00EA;
                                        }
                                        //this.HideAxControl();
                                    }
                                    goto Label_017F;
                                }
                            case 3:
                                {
                                    goto Label_01A7;
                                }
                            case 4:
                                {
                                    this.DoVerb(-1);
                                    this.SetOcState(8);
                                    continue;
                                }
                            default:
                                {
                                    goto Label_01A7;
                                }
                        }
                    Label_00EA:
                        //base.CreateControl(true);
                    Label_017F:
                        if (this.GetOcState() < 4)
                        {
                            this.SetOcState(4);
                        }
                        //this.OnInPlaceActive();
                        continue;
                    Label_01A7:
                        this.SetOcState(this.GetOcState() + 1);
                    }
                }
                finally
                {
                    this.axState[AxHost.inTransition] = false;
                }
            }
        }
 


        private void TransitionDownTo(int state)
        {
            if (!this.axState[AxHost.inTransition])
            {
                try
                {
                    this.axState[AxHost.inTransition] = true;
                    while (state < this.GetOcState())
                    {
                        switch (this.GetOcState())
                        {
                            case 1:
                                {
                                    this.ReleaseAxControl();
                                    this.SetOcState(0);
                                    continue;
                                }
                            case 2:
                                {
                                    this.StopEvents();
                                    this.DisposeAxControl();
                                    this.SetOcState(1);
                                    continue;
                                }
                            case 3:
                                
                                    this.SetOcState(this.GetOcState() - 1);
                                    break;
                                
                            case 4:
                                {
                                    if (!this.axState[AxHost.fFakingWindow])
                                    {
                                        InPlaceDeactivate();
                                        SetOcState(2);
                                        continue;
                                    }
                                    this.DestroyFakeWindow();
                                    this.SetOcState(2);
                                    SetOcState(2);
                                    continue;
                                }
                            case 8:
                                {
                                    UiDeactivate();
                                    SetOcState(4);
                                    continue;
                                }
                            default:
                                {
                                    if (GetOcState() != 0x10)
                                    {
                                        this.SetOcState(this.GetOcState() - 1);
                                        break;
                                    }
                                    this.SetOcState(8);
                                    continue;
                                }
                        }
                    }
                }
                finally
                {
                    this.axState[AxHost.inTransition] = false;
                }
            }
        }

            internal static bool FontToLogfont(Font font, LOGFONT lf)
            {
                GetObject(font.ToHfont(), Marshal.SizeOf(lf), lf);
                return true;
            }

            internal static bool FontToIFont(Font source, IFont target)
            {
                bool bRecreate = false;
                string fontName = target.GetName();
                if (source.Name != fontName)
                {
                    target.SetName(source.Name);
                    bRecreate = true;
                }
                float fTargetFontSize = ((float)target.GetSize()) / 10000f;
                float fSourceFontSize = source.Size * 1440f;
                if (fSourceFontSize != fTargetFontSize)
                {
                    target.SetSize((long)(fSourceFontSize * 10000f));
                    bRecreate = true;
                }
                LOGFONT lfSource = new LOGFONT();
                try
                {
                    FontToLogfont(source, lfSource);
                }
                finally
                {
                }
                short fntWeight = target.GetWeight();
                if (fntWeight != lfSource.lfWeight)
                {
                    target.SetWeight((short)lfSource.lfWeight);
                    bRecreate = true;
                }
                bool bBold = target.GetBold();
                if (bBold != (lfSource.lfWeight >= 700))
                {
                    target.SetBold(lfSource.lfWeight >= 700);
                    bRecreate = true;
                }
                bool bItalic = target.GetItalic();
                if (bItalic != (0 != lfSource.lfItalic))
                {
                    target.SetItalic(0 != lfSource.lfItalic);
                    bRecreate = true;
                }
                bool bUnderline = target.GetUnderline();
                if (bUnderline != (0 != lfSource.lfUnderline))
                {
                    target.SetUnderline(0 != lfSource.lfUnderline);
                    bRecreate = true;
                }
                bool bStrikeThrough = target.GetStrikethrough();
                if (bStrikeThrough != (0 != lfSource.lfStrikeOut))
                {
                    target.SetStrikethrough(0 != lfSource.lfStrikeOut);
                    bRecreate = true;
                }
                short charSet = target.GetCharset();
                if (charSet != lfSource.lfCharSet)
                {
                    target.SetCharset(lfSource.lfCharSet);
                    bRecreate = true;
                }
                return bRecreate;
            }



        [return: MarshalAs(UnmanagedType.Interface)]
        [DllImport("ole32.dll", PreserveSig = false)]
        public static extern object CoCreateInstance([In] ref Guid clsid, [MarshalAs(UnmanagedType.Interface)] object punkOuter, int context, [In] ref Guid iid);
 

        class AxContainer : IOleContainer, IOleInPlaceFrame
        {
            internal ContainerControl parent;
            private Hashtable components = new Hashtable();
            private AxHost siteUIActive;
            private AxHost siteActive;
            private Hashtable containerCache;

            internal AxContainer(ContainerControl parent)
            {
                this.containerCache = new Hashtable();
                this.parent = parent;
                //if (parent.Created)
                //{
                //    this.FormCreated();
                //}
            }
 
            private void ListAxControls(ArrayList list, bool fuseOcx)
            {
                Hashtable htComponents = GetComponents();
                if (htComponents != null)
                {
                    Control[] arrControls = new Control[htComponents.Keys.Count];
                    htComponents.Keys.CopyTo(arrControls, 0);
                    if (arrControls != null)
                    {
                        for (int i = 0; i < arrControls.Length; i++)
                        {
                            Control ctl = arrControls[i];
                            AxHost host = ctl as AxHost;
                            if (host != null)
                            {
                                /*
                                if (fuseOcx)
                                {
                                    list.Add(host.GetOcx());
                                }
                                else
                                {
                                    list.Add(ctl);
                                }
                                */
                                list.Add(ctl);
                            }
                        }
                    }
                }
            }
            private Hashtable GetComponents()
            {
                //return this.GetComponents(this.GetParentsContainer());
                return components;
            }

            internal void RemoveControl(Control ctl)
            {
                lock (this)
                {
                    if (this.containerCache.Contains(ctl))
                    {
                        this.containerCache.Remove(ctl);
                    }
                }
            }

            internal void OnUIActivate(AxHost site)
            {
                if (this.siteUIActive != site)
                {
                    if ((this.siteUIActive != null) && (this.siteUIActive != site))
                    {
                        try
                        {
                            siteUIActive.SetAxState(AxHost.ownDisposing, true);
                            siteUIActive.GetInPlaceObject().UIDeactivate();
                        }
                        finally
                        {
                            siteUIActive.SetAxState(AxHost.ownDisposing, siteUIActive.GetAxState(AxHost.ownDisposing));
                        }
                    }
                    //site.AddSelectionHandler();
                    this.siteUIActive = site;
                    //ContainerControl ctlCont = site.ContainingControl;
                    //if (ctlCont != null)
                    //{
                    //    ctlCont.ActiveControl = site;
                    //}
                }
            }

            internal void OnUIDeactivate(AxHost site)
            {
                siteUIActive = null;
                //site.RemoveSelectionHandler();
                //site.SetSelectionStyle(1);
                //site.editMode = 0;
                //if (site.GetSiteOwnsDeactivation())
                //{
                //    ContainerControl control2 = site.ContainingControl;
                //}
            }

            internal void OnInPlaceDeactivate(AxHost site)
            {
                if (this.siteActive == site)
                {
                    this.siteActive = null;
                    if (site.GetSiteOwnsDeactivation())
                    {
                        //this.parent.ActiveControl = null;
                    }
                }
            }

            #region IOleContainer Members

            int IOleContainer.ParseDisplayName(object pbc, string pszDisplayName, int[] pchEaten, object[] ppmkOut)
            {
                if (ppmkOut != null)
                {
                    ppmkOut[0] = null;
                }
                return E_NOTIMPL;
            }

            int IOleContainer.EnumObjects(int grfFlags, out IEnumUnknown ppenum)
            {
                ppenum = null;
                if ((grfFlags & 1) != 0)
                {
                    ArrayList alControls = new ArrayList();
                    this.ListAxControls(alControls, true);
                    if (alControls.Count > 0)
                    {
                        object[] arrControls = new object[alControls.Count];
                        alControls.CopyTo(arrControls, 0);
                        ppenum = new EnumUnknown(arrControls);
                        return 0;
                    }
                }
                ppenum = new EnumUnknown(null);
                return 0;
            }

            int IOleContainer.LockContainer(bool fLock)
            {
                return S_OK;
            }

            #endregion

            public IntPtr GetProxyForControl(Control c)
            {
                return IntPtr.Zero;
            }


            #region IOleInPlaceFrame Members

            IntPtr IOleInPlaceFrame.GetWindow()
            {
                return parent.Handle;
            }

            int IOleInPlaceFrame.ContextSensitiveHelp(int fEnterMode)
            {
                return S_OK;
            }

            int IOleInPlaceFrame.GetBorder(COMRECT lprectBorder)
            {
                return E_NOTIMPL;
            }

            int IOleInPlaceFrame.RequestBorderSpace(COMRECT pborderwidths)
            {
                return E_NOTIMPL;
            }

            int IOleInPlaceFrame.SetBorderSpace(COMRECT pborderwidths)
            {
                return E_NOTIMPL;
            }

            int IOleInPlaceFrame.SetActiveObject(IOleInPlaceActiveObject pActiveObject, string pszObjName)
            {
                if ((siteUIActive != null) && (siteUIActive.iOleInPlaceActiveObject != pActiveObject))
                {
                    if (siteUIActive.iOleInPlaceActiveObject != null)
                    {
                        Marshal.ReleaseComObject(siteUIActive.iOleInPlaceActiveObject);
                    }
                    siteUIActive.iOleInPlaceActiveObject = pActiveObject;
                }
                if (pActiveObject == null)
                {
                    /*
                    if (this.ctlInEditMode != null)
                    {
                        this.ctlInEditMode.editMode = 0;
                        this.ctlInEditMode = null;
                    }
                    */
                    return 0;
                }
                AxHost host = null;
                if (pActiveObject is IOleObject)
                {
                    IOleObject oleObj = (IOleObject)pActiveObject;
                    IOleClientSite site = null;
                    try
                    {
                        site = oleObj.GetClientSite();
                        if (site is OleSite)
                        {
                            host = ((OleSite)site).GetAxHost();
                        }
                    }
                    catch (COMException)
                    {
                    }
                    /*
                    if (this.ctlInEditMode != null)
                    {
                        this.ctlInEditMode.SetSelectionStyle(1);
                        this.ctlInEditMode.editMode = 0;
                    }
                    if (host == null)
                    {
                        this.ctlInEditMode = null;
                    }
                    else if (!host.IsUserMode())
                    {
                        this.ctlInEditMode = host;
                        host.editMode = 1;
                        host.AddSelectionHandler();
                        host.SetSelectionStyle(2);
                    }
                    */
                }
                return S_OK;
            }

            int IOleInPlaceFrame.InsertMenus(IntPtr hmenuShared, IntPtr lpMenuWidths)
            {
                return S_OK;
            }

            int IOleInPlaceFrame.SetMenu(IntPtr hmenuShared, IntPtr holemenu, IntPtr hwndActiveObject)
            {
                return E_NOTIMPL;
            }

            int IOleInPlaceFrame.RemoveMenus(IntPtr hmenuShared)
            {
                return E_NOTIMPL;
            }

            int IOleInPlaceFrame.SetStatusText(string pszStatusText)
            {
                return E_NOTIMPL;
            }

            int IOleInPlaceFrame.EnableModeless(bool fEnable)
            {
                return E_NOTIMPL;
            }

            int IOleInPlaceFrame.TranslateAccelerator(ref MSG lpmsg, short wID)
            {
                return S_FALSE;
            }

            #endregion
        }
        internal class EnumUnknown : IEnumUnknown
        {
            // Methods
            internal EnumUnknown(object[] arr)
            {
                this.arr = arr;
                this.loc = 0;
                this.size = (arr == null) ? 0 : arr.Length;
            }

            private EnumUnknown(object[] arr, int loc)
                : this(arr)
            {
                this.loc = loc;
            }

            void IEnumUnknown.Clone(out IEnumUnknown ppenum)
            {
                ppenum = new EnumUnknown(this.arr, this.loc);
            }

            int IEnumUnknown.Next(int celt, IntPtr rgelt, IntPtr pceltFetched)
            {
                if (pceltFetched != IntPtr.Zero)
                {
                    Marshal.WriteInt32(pceltFetched, 0, 0);
                }
                if (celt < 0)
                {
                    return -2147024809;
                }
                int nCount = 0;
                if (loc < size)
                {
                    while ((loc < size) && (nCount < celt))
                    {
                        if (arr[loc] != null)
                        {
                            Marshal.WriteIntPtr(rgelt, Marshal.GetIUnknownForObject(arr[loc]));
                            rgelt = (IntPtr)(((long)rgelt) + Marshal.SizeOf(typeof(IntPtr)));
                            nCount++;
                        }
                        loc++;
                    }
                }
                else
                {
                    nCount = 0;
                }
                if (pceltFetched != IntPtr.Zero)
                {
                    Marshal.WriteInt32(pceltFetched, 0, nCount);
                }
                if (nCount != celt)
                {
                    return S_FALSE;
                }
                return S_OK;
            }

            void IEnumUnknown.Reset()
            {
                loc = 0;
            }

            int IEnumUnknown.Skip(int celt)
            {
                loc += celt;
                if (loc >= size)
                {
                    return S_FALSE;
                }
                return S_OK;
            }

            // Fields
            private object[] arr;
            private int loc;
            private int size;
        }

        public enum OLEVERB
        {
            PRIMARY = (0),
            SHOW = (-1),
            OPEN = (-2),
            HIDE = (-3),
            UIACTIVATE = (-4),
            INPLACEACTIVATE = (-5),
            DISCARDUNDOSTATE = (-6),
        }

        [DllImport("coredll.dll")]
        public extern static int SetWindowPos(
           IntPtr hWnd, SetWindowPosZOrder pos,
           int X, int Y, int cx, int cy, SetWindowPosFlags uFlags);

        [DllImport("coredll.dll")]
        public extern static int GetObject(
           IntPtr hObj, int cbBuffer, LOGFONT lf);


        public enum SetWindowPosZOrder
        {
            HWND_TOP = 0,
            HWND_BOTTOM = 1,
            HWND_TOPMOST = -1,
            HWND_NOTOPMOST = -2,
            HWND_MESSAGE = -3
        }

        public enum SetWindowPosFlags
        {
            SWP_NOSIZE = 0x0001,
            SWP_NOMOVE = 0x0002,
            SWP_NOZORDER = 0x0004,
            SWP_NOREDRAW = 0x0008,
            SWP_NOACTIVATE = 0x0010,
            SWP_FRAMECHANGED = 0x0020,
            SWP_SHOWWINDOW = 0x0040,
            SWP_HIDEWINDOW = 0x0080,
            SWP_NOCOPYBITS = 0x0100,
            SWP_NOOWNERZORDER = 0x0200,
            SWP_NOSENDCHANGING = 0x0400,
            SWP_DRAWFRAME = SWP_FRAMECHANGED,
            SWP_NOREPOSITION = SWP_NOOWNERZORDER,
            SWP_DEFERERASE = 0x2000,
            SWP_ASYNCWINDOWPOS = 0x4000
        }

    }
}
